/***************************************************
指数处理模块：  
    负责处理除法的指数相减 和 开方的指数处理
    
    双精度数的指数范围：2046-1 偏置：1023 实际指数范围：1023~（-1022）
****************************************************/

module exp_handle(  

    input                       code                ,   //1:除法   0:开方

    input       [11-1:0]        exp1                ,   //操作数1的指数
    input       [11-1:0]        exp2                ,   //操作数2的指数

    input                       signal_double       ,   // 1:单精度    0:双精度

    /*
    如何确定输出指数的位宽：（x代表后面的其他位）

        因为两个数相除，指数只会相减，指数只会减小。
        指数相减的结果的最大值为：指数最大值减最小值，为2045，
        指数相减的结果的最小值为：指数最小值减最大值，为-2045
        因为指数相减会有负数，所以要加符号位，具体减法结果符号位的位宽是多少由以下讨论决定。

//        当尾数是 规格化数 / 规格化数 时： 
//            当最小的规格化数 除 最大的规格化数时，结果最小，尾数为1.0(x) / 1.11(x) = 0.1(x)， 指数结果为(1-2046=-2045)
//            当最大的规格化数 除 最小的规格化数时，结果最大，尾数为1.11(x) / 1.0(x) = 1.11(x)， 指数结果为(2046-1=2045)
//            (尾数只会不移位或者左移一位，所以指数只会变小，且只会变小一位)
//
//        当尾数是 规格化数 / 非规格化数 时： 想知道结果的范围就要采用极限的思想。
//            当最小的规格化数 除 最大的非规格化数时，结果最小，尾数结果为1.0 / 0.111(x) = 1.(x)， 指数结果为0
//            当最大的规格化数 除 最小的非规格化数时，结果最大，尾数结果为1.111(x) / 0.0……1 = 111(x)， 指数结果为2046-1 = 2045
//            因为规格化数 除 非规格化数，尾数只会变大，尾数只会右移，只会出现本来在范围内的指数因为尾数的移位而溢出的情况。
//            (尾数只会不移位或者最多右移52位，所以指数只会变大)
//
//        当尾数是 非规格化数 / 规格化数的时候 ：
//            当最小的非规格化数 除 最大的规格化数时，结果最小，尾数为0.0000……01 / 1.1111(x) = 0.000……001(x)  指数为(1-2046=-2045)
//            当最大的非规格化数 除 最小的规格化数时，结果最大，尾数为0.11111(x) / 1.000(x) = 0.1111(x)，指数为(1-1=0)
//            (尾数只会左移，尾数左移变大，指数变小)
//
//        当尾数是 非规格化数 / 非规格化数的时候 ：
//            当最小的非规格化数 除 最大的非规格化数时，结果最小，尾数为0.000……01 / 0.111(x) = 0.000……001(x)， 指数为(1-1=0)
//            当最大的非规格化数 除 最小的非规格化数时，结果最大，尾数为0.111(x) / 0.000……01 = 1111(x) ，指数为(1-1=0)
//            (尾数即有可能左移也有可能右移，指数即可以变大，也可以变小，但是指数变动范围在53位左右，11位的指数位足够使用)
//
//        因为在指数运算的时候判断结果是否超范围会导致情况特别复杂，所以数据溢出判断放到最终数据规格化之后
//        综上，指数位宽为11位有效位和一位符号位
    */

    //(没有加上偏置，因为两个数相减偏置被减掉了)
    //(12位代表一个符号位和11个指数位)
    //(不加偏置上是因为指数会根据尾数前面的零进行调整，在调整的时候再加偏置)
    output      [12-1:0]        exp_out                //输出的指数



);

//加法器采用并行前缀加法器，并行前缀加法器有三种，LF、KS、BK，也可以将前三种的结构组合在一起形成新的加法器结构
wire        [11-1:0]            exp2_inv        ;
wire        [12-1:0]            sign_exp1       ;
wire        [12-1:0]            sign_exp2_inv   ;

//加法器的中间变量
wire        [12-1:0]            p               ;
wire        [12-1:0]            g               ;

wire        [12-1:0]            level1_p        ;
wire        [12-1:0]            level1_Q        ;

wire        [12-1:0]            level2_p        ;
wire        [12-1:0]            level2_Q        ;

wire        [12-1:0]            level3_p        ;
wire        [12-1:0]            level3_Q        ;

wire        [12-1:0]            level4_p        ;
wire        [12-1:0]            level4_Q        ;



assign exp2_inv = ~exp2;
assign sign_exp1 = {1'b0, exp1};        //给操作数1的指数扩一位符号位
assign sign_exp2_inv = {1'b1, exp2_inv};    //给操作数2的指数扩展负的符号位，补码加一的一放在后面移位加偏置的时候再加上

//要运算的数据一共有12位，所以要有四级运算
//代码中采用KS加法器，加法器第一步，首先生成每个bit的p、g变量
assign p = sign_exp1 ^ sign_exp2_inv;
assign g = sign_exp1 & sign_exp2_inv;

//加法器 根据p，g算出第一层的P，Q      P=Pi & Pi-1   Qi=Pi & Qi-1 | gi
assign level1_p = p;
assign level1_Q[11:1] = ( level1_p[11:1] & g[10:0] ) | g[11:1];
assign level1_Q[0] = g[0];

//加法器 算出第二层的P,Q
assign level2_p = level1_p & {level1_p[10:0], 1'b0};
assign level2_Q[11:2] = (level2_p[11:2] & level1_Q[9:0]) | level1_Q[11:2];
assign level2_Q[1:0] = level1_Q[1:0];

//加法器 算出第三层的P，Q
assign level3_p = level2_p & {level2_p[7:0], 4'b0};
assign level3_Q[11:4] = (level3_p[11:4] & level2_Q[7:0]) | level2_Q[11:4];
assign level3_Q[3:0] = level2_Q[3:0];


//加法器 算出第四层的P，Q
assign level4_p = level3_p & {level3_p[3:0], 8'b0};
assign level4_Q[11:8] = (level4_p[11:8] & level3_Q[3:0]) | level3_Q[11:8];
assign level4_Q[7:0] = level3_Q[7:0];

//输出最终结果
assign exp_out = {level4_Q[10:0], 1'b0} ^ p;





endmodule